package com.education.service.ucenter.controller.web;

import com.education.common.utils.HttpClientUtils;
import com.education.exception.OnlineEducationException;
import com.education.helper.JwtHelper;
import com.education.helper.JwtInfo;
import com.education.result.ResultCodeEnum;
import com.education.service.ucenter.entity.Member;
import com.education.service.ucenter.service.MemberService;
import com.education.service.ucenter.utils.UcenterProperties;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.UUID;

/**
 * 微信登录接口
 * Created by Lance on 2020/07/07 13:00
 */
@Slf4j
@Controller //注意这里没有配置 @RestController
@RequestMapping("/api/ucenter/wx")
public class WebWeChatController {

    @Autowired
    private UcenterProperties ucenterProperties;

    @Autowired
    private MemberService memberService;

    /**
     * 微信登录 - 生成二维码超链接
     *
     * @param session
     * @return
     */
    @GetMapping("login")
    public String genQrConnect(HttpSession session) {

        // 原链接生成二维码 :  https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
        // 授权服务器的核心接口
        String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
                // %s 占位符
                "?appid=%s" +
                "&redirect_uri=%s" +
                "&response_type=code" +
                "&scope=snsapi_login" +
                "&state=%s" +
                "#wechat_redirect";

        // redirect_uri：被微信服务器调用的本地接口地址
        String encodeUri = "";
        try {
            String redirectUri = ucenterProperties.getRedirectUri();
            // 使用URL 编码
            encodeUri = URLEncoder.encode(redirectUri, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.error(ExceptionUtils.getStackTrace(e));
            throw new OnlineEducationException(ResultCodeEnum.URL_ENCODE_ERROR);
        }

        //state：用于保持请求和回调的状态，授权请求后原样带回给第三方。该参数可用于防止csrf 跨站点攻击
        String state = UUID.randomUUID().toString();
        System.out.println("生成的state = " + state);
        session.setAttribute("wx_open_state", state);

        //生成二维码的超链接
        String qrcodeUrl = String.format(
                baseUrl,
                ucenterProperties.getAppId(),
                encodeUri,
                state);

        //客户端跳转
        return "redirect:" + qrcodeUrl;
    }

    /**
     * 微信登录成功后返回的地址
     *
     * @param code
     * @param state
     * @return
     */
    @GetMapping("callback")
    public String callback(String code, String state, HttpSession session) {
        System.out.println("callback被调用");
        System.out.println("code = " + code);
        System.out.println("state = " + state);

        // 第一步 : 非空校验 code 和 state 是否为空或者不合法
        if (StringUtils.isEmpty(code) || StringUtils.isEmpty(state)) {
            log.error("非法的回调!!!");
            throw new OnlineEducationException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR);
        }
        // 第二步 :  从 session 中获取 state
        String wechatOpenState = (String) session.getAttribute("wx_open_state");
        if (!state.equals(wechatOpenState)) {
            log.error("非法的回调!!!");
            throw new OnlineEducationException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR);
        }
        // 使用 HttpClient 携带 code 获取 access_token
        // 1.组装请求url
        String accessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token";
//                "?appid=APPID" +
//                "&secret=SECRET" +
//                "&code=CODE" +
//                "&grant_type=authorization_code";

        HashMap<String, String> accessTokenParam = new HashMap<>();
        // 组装URL参数
        accessTokenParam.put("appid", ucenterProperties.getAppId());
        accessTokenParam.put("secret", ucenterProperties.getAppSecret());
        accessTokenParam.put("code", code);
        accessTokenParam.put("grant_type", "authorization_code");
        // 2.创建 HttpClientUtils 对象
        HttpClientUtils clientUtils = new HttpClientUtils(accessTokenUrl, accessTokenParam);

        // 发送请求
        String result = "";
        try {
            // 3.发送请求
            clientUtils.setHttps(true);
            clientUtils.get();
            // 4.获取响应结果
            result = clientUtils.getContent();
            System.out.println("result = " + result);
        } catch (Exception e) {
            log.error("获取 access_token 失败====>" + ExceptionUtils.getStackTrace(e));
            throw new OnlineEducationException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR);
        }
        // 5.解析 json 结果
        Gson gson = new Gson();
        HashMap resultMap = gson.fromJson(result, HashMap.class);

        // 错误结果: {"errcode":40029,"errmsg":"invalid code"}
        Object errcodeObj = resultMap.get("errcode");
        Object errmsgObj = resultMap.get("errmsg");
        // 6.判断业务失败
        if (errcodeObj != null) {
            Double errcodeCode = (Double) errcodeObj;
            String errmsgCode = (String) errmsgObj;
            log.error("获取 access_token 失败====>" + errcodeCode + " --- " + errmsgCode);
            throw new OnlineEducationException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR);
        }
        // 7.获取 access_token 和 openId
        String accessToken = (String) resultMap.get("access_token");
        String openId = (String) resultMap.get("openid");

        System.out.println("accessToken = " + accessToken);
        System.out.println("openId = " + openId);

        // 三、查询用户是否存在：存在（数据库中查询用户信息）、不存在（调用远程接口查找用户信息，注册）
        Member member = memberService.getByOpenid(openId);
        if (member == null) {
            // 第四步 : 携带 access_token 获取用户信息
            // 1.组装请求url
            String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
                    "?access_token=" + accessToken +
                    "&openid=" + openId;
            // 2.创建 HttpClientUtils 对象
            clientUtils = new HttpClientUtils(baseUserInfoUrl);
            String resultUserInfo = "";
            // 如果发送异常 : 为网络异常
            try {
                //  3.发送请求
                clientUtils.setHttps(true);
                clientUtils.get();
                // 4.获取响应结果
                resultUserInfo = clientUtils.getContent();
                System.out.println("result = " + result);
            } catch (Exception e) {
                log.error("获取用户信息失败====>" + ExceptionUtils.getStackTrace(e));
                throw new OnlineEducationException(ResultCodeEnum.FETCH_USERINFO_ERROR);
            }

            // 5.解析响应结果
            HashMap resultUserInfoMap = gson.fromJson(resultUserInfo, HashMap.class);
            // 错误结果: {"errcode":40029,"errmsg":"invalid code"}
            // 6.处理业务失败
            errcodeObj = resultUserInfoMap.get("errcode");
            errmsgObj = resultUserInfoMap.get("errmsg");
            if (errcodeObj != null) {
                Double errcodeCode = (Double) errcodeObj;
                String errmsgCode = (String) errmsgObj;
                log.error("获取用户信息失败====>" + errcodeCode + " --- " + errmsgCode);
                throw new OnlineEducationException(ResultCodeEnum.FETCH_USERINFO_ERROR);
            }
            // 7.从结果中获取用户信息
            String nickname = (String) resultUserInfoMap.get("nickname");   // 姓名
            String headimgurl = (String) resultUserInfoMap.get("headimgurl");   // 头像
            Double sex = (Double) resultUserInfoMap.get("sex");   // 性别

            // 将用户头像存储到 oss服务器上

            // 第五步 : 将用户信息插入到数据库中,完成用户注册
            member = new Member();
            member.setOpenid(openId);
            member.setNickname(nickname);
            member.setAvatar(headimgurl);   // 存储oss服务器上的地址
            member.setSex(sex.intValue());
            // 微信扫码注册 并保存到数据库中
            memberService.save(member);
        }

        // 第六步 : 生成 JWT 完成登录
        JwtInfo jwtInfo = new JwtInfo();
        jwtInfo.setId(member.getId());
        jwtInfo.setNickname(member.getNickname());
        jwtInfo.setAvatar(member.getAvatar());
        String token = JwtHelper.createToken(jwtInfo);
        // 登录成功跳转到首页面
        return "redirect:http://localhost:3333?token=" + token;
    }
}
